import consts
import broker
import httpx
import logging
import quote
import sys
import strategy
import socket

logging.basicConfig(
    stream=sys.stdout, level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(name)s - %(message)s'
)


class Worker:
    def __init__(self, config):
        self.config = config
        self.logger = logging.getLogger()
        self.broker = broker.XTPBroker(self)
        self.strategy = strategy.Strategy(self)
        self.session_id = 0
        self.request_id = 1
        self.position_info = dict()
        self.unfinished_order_info = dict()
        self.assign_info = dict()
        self.margin_info = dict()
        self.asset_info = dict(
            total_asset=0, buying_power=0, security_asset=0, fund_buy_amount=0, fund_buy_fee=0, fund_sell_amount=0,
            fund_sell_fee=0, withholding_amount=0, account_type=0, frozen_margin=0, frozen_exec_cash=0,
            frozen_exec_fee=0, pay_later=0, preadva_pay=0, orig_banlance=0, banlance=0, deposit_withdraw=0,
            trade_netting=0, captial_asset=0, force_freeze_amount=0, preferred_amount=0, repay_stock_aval_banlance=0,
            fund_order_data_charges=0, fund_cancel_data_charges=0, exchange_cur_risk_degree=0, company_cur_risk_degree=0,
            unknown=0
        )
        self.fund_info = dict(
            maintenance_ratio=0, all_asset=0, all_debt=0,
            line_of_credit=0, guaranty=0, reserved=0
        )
        self.quote_info = quote.Quote()

    @property
    def log_path(self):
        return '/tmp/xtp/' + self.config.investor_id

    @property
    def local_ipv4(self):
        name = socket.gethostname()
        ipv4 = socket.gethostbyname(name)
        return ipv4

    def req_query_margin_info(self):
        resp = httpx.get('https://xtp.zts.com.cn/api/v1/apiuser/getcredittarget?pageindex=1&pagesize=10000')
        resp = resp.json()
        self.on_query_margin_info(resp['data'])

    def req_login(self):
        session_id = self.broker.login(
            self.config.host, self.config.port,
            self.config.investor_id, self.config.password,
            1, self.local_ipv4
        )
        if not session_id:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.session_id = session_id

    def req_query_asset(self):
        result = self.broker.queryAsset(self.session_id, self.request_id)
        if result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.request_id += 1

    def req_query_credit_fund_info(self):
        result = self.broker.queryCreditFundInfo(self.session_id, self.request_id)
        if result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.request_id += 1

    def req_query_credit_ticker_assign_info(self):
        query_param = {
            'market': 0,
            'symbol': 0
        }
        result = self.broker.queryCreditTickerAssignInfo(query_param, self.session_id, self.request_id)
        if result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.request_id += 1

    def req_query_position(self, symbol):
        result = self.broker.queryPosition(symbol, self.session_id, self.request_id)
        if result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.request_id += 1

    def req_query_unfinished_orders_ex(self):
        result = self.broker.queryUnfinishedOrdersEx(self.session_id, self.request_id)
        if result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.unfinished_order_info = dict()
            self.request_id += 1

    def req_insert_order(self, market, symbol, price, quantity, side, price_type, position_effect, business_type, order_client_id):
        order_info = {
            'ticker': symbol,
            'market': consts.CUSTOM_MARKET_TYPE_MAP[market],
            'price_type': price_type,
            'price': price,
            'quantity': quantity,
            'side': side,
            'position_effect': position_effect,
            'order_client_id': order_client_id,
            'business_type': business_type
        }
        order_xtp_id = self.broker.insertOrder(order_info, self.session_id)
        if not order_xtp_id:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
            return None
        else:
            order_info.update(dict(order_xtp_id=order_xtp_id))
            return order_info

    def req_cancel_order(self, order_xtp_id):
        order_cancel_xtp_id = self.broker.cancelOrder(order_xtp_id, self.session_id)
        if not order_cancel_xtp_id:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        else:
            self.on_cancel_order(order_cancel_xtp_id, order_xtp_id)

    def req_query_order_by_xtp_id(self, order_xtp_id):
        result = self.broker.queryOrderByXTPID(order_xtp_id, self.session_id, self.request_id)
        if not result:
            error_info = self.broker.getApiLastError()
            self.on_error(error_info)
        self.request_id += 1

    def on_query_margin_info(self, margin_info):
        for item in margin_info:
            self.margin_info[item['stk_code']] = item

    def on_disconnected(self, session_id, reason):
        self.logger.info(f'on_disconnected: session_id={session_id}, reason={reason}')
        self.session_id = 0
        self.req_login()

    def on_error(self, error_info):
        if error_info and error_info['error_id']:
            self.logger.error('on_error: id={error_id}, msg={error_msg}'.format(**error_info))

    def on_cancel_order(self, order_cancel_xtp_id, order_xtp_id):
        self.logger.info(f'on_cancel_order: order_cancel_xtp_id={order_cancel_xtp_id}, order_xtp_id={order_xtp_id}')

    def on_query_account_trade_market(self, trade_location, error_info, request_id, session_id):
        pass

    def on_order_event(self, order_info, error_info, session_id):
        self.logger.info(f'on_order_event: order_info={order_info}, error_info={error_info}, session_id={session_id}')
        self.strategy.on_order(order_info, error_info)

    def on_trade_event(self, trade_info, session_id):
        self.logger.info(f'on_trade_event: trade_info={trade_info}, session_id={session_id}')
        self.strategy.on_trade(trade_info)

    def on_cancel_order_error(self, cancel_info, error_info, session_id):
        pass

    def on_query_order(self, order_info, error_info, request_id, is_last, session_id):
        self.logger.info(f'on_query_order: order_info={order_info}, error_info={error_info}, request_id={request_id}, is_last={is_last}, session_id={session_id}')

    def on_query_order_ex(self, order_info, error_info, request_id, is_last, session_id):
        self.logger.info(f'on_query_order_ex: order_info={order_info}, error_info={error_info}, request_id={request_id}, is_last={is_last}, session_id={session_id}')
        self.unfinished_order_info[order_info['order_xtp_id']] = order_info

    def on_query_order_by_page(self, order_info, req_count, order_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_order_by_page_ex(self, order_info, req_count, order_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_trade(self, trade_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_trade_by_page(self, trade_info, req_count, order_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_position(self, position_info, error_info, request_id, is_last, session_id):
        # self.logger.info(f'on_query_position: position_info={position_info}, error_info={error_info}, request_id={request_id}, is_last={is_last}, session_id={session_id}')
        self.position_info[position_info['ticker']] = position_info

    def on_query_asset(self, asset_info, error_info, request_id, is_last, session_id):
        self.logger.info(f'on_query_asset: asset_info={asset_info}, error_info={error_info}, request_id={request_id}, is_last={is_last}, session_id={session_id}')
        self.asset_info = asset_info

    def on_query_structured_fund(self, fund_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_fund_transfer(self, fund_transfer_info, error_info, request_id, is_last, session_id):
        pass

    def on_fund_transfer(self, fund_transfer_info, error_info, request_id, session_id):
        pass

    def on_query_etf(self, etf_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_etf_basket(self, etf_component_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_ipo_info_list(self, ipo_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_ipo_quota_info(self, quota_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_bond_ipo_info_list(self, ipo_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_bond_swap_stock_info(self, swap_stock_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_auction_info(self, option_info, error_info, request_id, is_last, session_id):
        pass

    def on_credit_cash_repay(self, cash_repay_info, error_info, session_id):
        pass

    def on_credit_cash_repay_debt_interest_fee(self, cash_repay_info, error_info, session_id):
        pass

    def on_query_credit_cash_repay_info(self, cash_repay_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_credit_fund_info(self, fund_info, error_info, request_id, session_id):
        self.logger.info(f'on_query_credit_fund_info: fund_info={fund_info}, error_info={error_info}, request_id={request_id}, session_id={session_id}')
        self.fund_info = fund_info

    def on_query_credit_debt_info(self, debt_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_credit_ticker_debt_info(self, debt_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_credit_asset_debt_info(self, remain_amount, error_info, request_id, session_id):
        pass

    def on_query_credit_ticker_assign_info(self, assign_info, error_info, request_id, session_id):
        self.logger.info(f'on_query_credit_ticker_assign_info: assign_info={assign_info}, error_info={error_info}, request_id={request_id}, session_id={session_id}')

    def on_query_credit_excess_stock(self, stock_info, error_info, request_id, session_id):
        pass

    def on_query_mul_credit_excess_stock(self, stock_info, error_info, request_id, is_last, session_id):
        pass

    def on_credit_extend_debt_date(self, debt_extend_info, error_info, session_id):
        pass

    def on_query_credit_extend_debt_date_orders(self, debt_extend_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_credit_fund_extra_info(self, fund_info, error_info, request_id, session_id):
        pass

    def on_query_credit_position_extra_info(self, fund_info, error_info, request_id, is_last, session_id):
        pass

    def on_option_combined_order_event(self, order_info, error_info, request_id, is_last, session_id):
        pass

    def on_option_combined_trade_event(self, trade_info, session_id):
        pass

    def on_cancel_option_combined_order_error(self, cancel_info, error_info, session_id):
        pass

    def on_query_option_combined_orders(self, order_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_combined_orders_ex(self, order_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_combined_orders_by_page(self, order_info, req_count, order_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_option_combined_orders_by_page_ex(self, order_info, req_count, order_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_option_combined_trades(self, trade_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_combined_trades_by_page(self, trade_info, req_count, trade_sequence, query_reference, request_id, is_last, session_id):
        pass

    def on_query_option_combined_position(self, position_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_combined_strategy_info(self, strategy_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_option_combined_exec_position(self, position_info, error_info, request_id, is_last, session_id):
        pass

    def on_query_other_server_fund(self, fund_info, error_info, request_id, session_id):
        pass

    def on_query_strategy(self, strategy_info, strategy_param, error_info, request_id, is_last, session_id):
        pass

    def on_strategy_state_report(self, strategy_state, session_id):
        pass

    def on_algo_user_establish_channel(self, user, error_info, session_id):
        pass

    def on_insert_algo_order(self, strategy_info, error_info, session_id):
        pass

    def on_cancel_algo_order(self, strategy_info, error_info, session_id):
        pass

    def on_algo_disconnected(self, reason):
        pass

    def on_algo_connected(self):
        pass

    def on_strategy_symbol_state_report(self, strategy_symbol_state, session_id):
        pass

    def on_new_strategy_create_report(self, strategy_info, strategy_param, session_id):
        pass

    def on_strategy_recommendation(self, basket_flag, recommendation_info, strategy_param, error_info, request_id, is_last, session_id):
        pass

    def on_modify_algo_order(self, data, error, session_id):
        pass

    def on_pause_algo_order(self, xtp_strategy_id, ticker_info, error_info, request_id, session_id):
        pass

    def on_resume_algo_order(self, xtp_strategy_id, ticker_info, error_info, request_id, session_id):
        pass

    def start(self):
        self.broker.createTraderApi(1, self.log_path, 4)
        self.broker.subscribePublicTopic(2)
        self.broker.setSoftwareKey(self.config.software_key)
        self.broker.setHeartBeatInterval(15)
        self.strategy.start()
